﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Threading;
using SharpDX.XAudio2;
using ScheduledXAudio2;
using SynergyControls;
using SynergyLib.DSP;

namespace XAudio2Controls
{
    /// <summary>
    /// Class from which DrumPatchTabPanel (and a synthesizer panel, eventually) inherits.
    /// </summary>
    public abstract class XA2TabPanelBase : CustomControlBase, INotifyPropertyChanged
    {
        #region Fields        
        protected bool iscurrentlyselected;
        private List<FrameworkElement> RetrievedTemplateChildren = new List<FrameworkElement>();
        internal PatchHost SoundEngine;
        protected ComboBox ComboBoxPatches { get { return ResourceRoot.FindName("PART_ComboBoxPatches") as ComboBox; } }
        protected TabControl TabItemParent { get { return ResourceRoot.FindName("PART_TabItemParent") as TabControl; } }        
        protected TabItem TabPatch { get { return ResourceRoot.FindName("PART_TabPatch") as TabItem;} }        
        protected TabItem TabShape { get { return ResourceRoot.FindName("PART_TabShape") as TabItem; } }
        internal TabItem TabPattern { get { return ResourceRoot.FindName("PART_TabPattern") as TabItem; } }
        internal TabItem TabSubmixer { get { return ResourceRoot.FindName("PART_TabSubmixer") as TabItem; } }        
        internal TabItem TabEffects { get { return ResourceRoot.FindName("PART_TabEffects") as TabItem; } }
        internal Collection<TabItem> Tabs;
        protected StackPanel TabPatchPanel { get { return ResourceRoot.FindName("PART_TabPatchPanel") as StackPanel; } }
        protected StackPanel PatchInfoPanel { get { return ResourceRoot.FindName("PART_PatchInfoPanel") as StackPanel; } }
        internal Grid TabShapePanel { get { return ResourceRoot.FindName("PART_TabShapePanel") as Grid; } }
        internal StackPanel TabPatternPanel
        {
            get
            {
                try
                {
                    return ResourceRoot.FindName("PART_TabPatternPanel") as StackPanel;
                }
                catch (NullReferenceException)
                {
                    return null;
                }
            }
        }
        protected StackPanel TabSubmixerPanel { get { return ResourceRoot.FindName("PART_TabSubmixerPanel") as StackPanel; } }
        protected TextBox NewDirectoryTextBox { get { return ResourceRoot.FindName("PART_NewDirectory") as TextBox; } }
        protected StackPanel TabEffectsPanel { get { return ResourceRoot.FindName("PART_TabEffectsPanel") as StackPanel; } }
        protected RadioButton RadioBtnSamples { get { return ResourceRoot.FindName("PART_RadioBtnSamples") as RadioButton; } }
        protected RadioButton RadioBtnFromFile { get { return ResourceRoot.FindName("PART_RadioBtnFromFile") as RadioButton; } }
        protected Button BtnDirectoryBrowse { get { return ResourceRoot.FindName("PART_BtnDirectoryBrowse") as Button; } }
        protected Button ButtonAddFx { get { return ResourceRoot.FindName("PART_ButtonAddFx") as Button; } }
        protected ComboBox ComboBoxSelectFx { get { return ResourceRoot.FindName("PART_ComboBoxSelectFx") as ComboBox; } }
        protected SubmixVoice PrimarySubmixer;
        protected Thread PatchThread;
        protected string filePath = "Load file in Patch tab";       
        protected GraphingEffect Grapher;
        protected EffectDescriptor GrapherED;
        private int id_dispenser_integer = 0;
        private int phrase_id_dispenser_integer = 1;
        #endregion Fields

        #region Events

        public event RoutedEventHandler WasSelected;
        public event RoutedEventHandler SelectedTabChanged;

        #endregion Events

        #region Properties
        public bool IsCurrentlySelected
        {
            get
            {
                return iscurrentlyselected;
            }
            protected set
            {
                if (ParentRef.Patches != null)
                {
                    foreach (XA2TabPanelBase tpb in ParentRef.Patches)
                    {
                        if (tpb != this)
                        { tpb.iscurrentlyselected = false; }

                    }
                }
                iscurrentlyselected = value;
            }
        }
        internal int Bar_ID_Dispenser_Property
        {
            get 
            { 
                if (TabPatternPanel != null)
                    ++id_dispenser_integer;
            return id_dispenser_integer;
            }            
        }
        internal int Phrase_ID_Dispenser_Property
        {
            get
            {                
                return phrase_id_dispenser_integer;
            }
        }
        internal bool HasTemplateChildren { get; set; }
      
        public ObservableCollection<RhythmButtonBar> Bars
        {
            get;
            protected set;
        }
        protected Collection<EffectDescriptor> FxChain
        { get; set; }
        public string FilePath
        {
            get
            { 
                return filePath; 
            }
            set
            {
                filePath = value;
                NotifyPropertyChanged("FilePath");
            }
        }
        protected XA2PatchBase ParentRef
        {
            get { return ResourceRoot.FindParent<XA2PatchBase>(); }
        }
        protected Thread ParentRefThread
        {
            get { return ParentRef.PatchControlThread; }
        }
        public bool IsTerminal
        {
            get;
            protected set;
        }
        #endregion Properties

        #region Dependency Properties
        #region File Directory

        private static readonly DependencyProperty FileDirectoryProperty =
            DependencyProperty.Register("FileDirectory",
            typeof(string),
            typeof(XA2TabPanelBase),
            new PropertyMetadata(new PropertyChangedCallback(FileDirectoryChanged)));
        protected static void FileDirectoryChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs args)
        {
            XA2TabPanelBase instance = dependency as XA2TabPanelBase;
            if (instance != null)
            {
                instance.FileDirectoryChanged(instance.FileDirectory);
            }
        }
        protected virtual void FileDirectoryChanged(string newvalue)
        {
            CoerceComboBoxPatchesItemsSource();
            NewDirectoryTextBox.Text = newvalue;
            
        }
        public string FileDirectory
        {
            get { return (string)GetValue(FileDirectoryProperty); }
            protected set {                 
                SetValue(FileDirectoryProperty, value); }
        }

        #endregion File Directory
        #region Patch Source

        private static readonly DependencyProperty PatchSourceProperty =
            DependencyProperty.Register("PatchSource",
            typeof(PatchSource),
            typeof(XA2TabPanelBase),
            new PropertyMetadata(new PropertyChangedCallback(PatchSourceChanged)));
        protected static void PatchSourceChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs args)
        {
            XA2TabPanelBase instance = dependency as XA2TabPanelBase;
            if (instance != null)
            {                
                instance.PatchSourceChanged((PatchSource)args.NewValue, (PatchSource)args.OldValue);
            }
        }
        protected virtual void PatchSourceChanged(PatchSource newvalue, PatchSource oldvalue)
        {
            ComboBoxPatches.ItemsSource = null;
            switch (newvalue)
            { 
                case PatchSource.FromFilePath:                    
                        ComboBoxPatches.ItemsSource = SynergyLib.Friendly.FileGetter.GetFilesList();
                    break;
                case PatchSource.FromStream:
                    //List<System.IO.Stream> temp = new List<System.IO.Stream>() { bassdrum, cleansnare, heavysnare, ride, gatedhit };
                    
                    //ComboBoxPatches.ItemsSource = temp;
                    ComboBoxPatches.ItemsSource = GetIncludedWavs();
                    /*
                    string[] composite = new string[] { "bass, snare, snare2, ride, gatedhit" };
                    try
                    {
                        for (int i = 0; i < ComboBoxPatches.Items.Count; i++)
                        {
                            var variable = ComboBoxPatches.Items[i] as ComboBoxItem;
                            variable.Tag = composite[i];
                            variable.ContentStringFormat = variable.Tag.ToString();
                        }
                    }
                    catch (NullReferenceException)
                    { break; }
                    */
                    break;
            }
            (ResourceRoot.FindName("PART_PatchSourceLabel") as Label).Content = newvalue.ToString();
        }
        protected virtual void CoerceComboBoxPatchesItemsSource()
        {
                switch (patchsource)
                {
                    case PatchSource.FromFilePath:
                        ComboBoxPatches.ItemsSource = SynergyLib.Friendly.FileGetter.GetFilesList();
                        break;
                    case PatchSource.FromStream:
                        ComboBoxPatches.ItemsSource = GetIncludedWavs();
                        break;
                }
        }
        protected PatchSource patchsource
        {
            get { return (PatchSource)GetValue(PatchSourceProperty); }
            set { SetValue(PatchSourceProperty, value); }
        }

        #endregion Patch source
        #region Patch Channels
        public static readonly DependencyProperty PatchChannelsProperty =
            DependencyProperty.Register("PatchChannels",
            typeof(int),
            typeof(XA2TabPanelBase),
            new PropertyMetadata(new PropertyChangedCallback(PatchChannelsChanged)));

        private static void PatchChannelsChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs args)
        {
            XA2TabPanelBase instance = dependency as XA2TabPanelBase;
            if (instance != null)
            {
                (instance.ResourceRoot.FindName("PART_ChannelsLabel") as Label).Content = instance.PatchChannels.ToString() + " Channels";
            }
        }
        public int PatchChannels
        {
            get
            {
                return (int)GetValue(PatchChannelsProperty);
            }
            set
            {
                SetValue(PatchChannelsProperty, value);
            }
        }
        #endregion Patch SampleRate
        #region Patch SampleRate
        public static readonly DependencyProperty PatchSampleRateProperty =
            DependencyProperty.Register("PatchSampleRate",
            typeof(int),
            typeof(XA2TabPanelBase),
            new PropertyMetadata(new PropertyChangedCallback(PatchSampleRateChanged)));

        private static void PatchSampleRateChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs args)
        {
            XA2TabPanelBase instance = dependency as XA2TabPanelBase;
            if (instance != null)
            {
                (instance.ResourceRoot.FindName("PART_SampleRateLabel") as Label).Content = instance.PatchSampleRate.ToString() + " samples/sec";
            }
        }
        public int PatchSampleRate
        {
            get
            {
                return (int)GetValue(PatchSampleRateProperty);
            }
            set
            {
                SetValue(PatchSampleRateProperty, value);
            }
        }
        #endregion Patch SampleRate
        #region Patch AvgBytesPerSec
        public static readonly DependencyProperty PatchAvgBytesPerSecProperty =
           DependencyProperty.Register("PatchAvgBytesPerSec",
           typeof(int),
           typeof(XA2TabPanelBase),
           new PropertyMetadata(new PropertyChangedCallback(PatchAvgBytesPerSecChanged)));

        private static void PatchAvgBytesPerSecChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs args)
        {
            XA2TabPanelBase instance = dependency as XA2TabPanelBase;
            if (instance != null)
            {
                (instance.ResourceRoot.FindName("PART_AvgBytesPersSecLabel") as Label).Content = instance.PatchAvgBytesPerSec.ToString() + " average bytes/sec";
            }
        }
        public int PatchAvgBytesPerSec
        {
            get
            {
                return (int)GetValue(PatchAvgBytesPerSecProperty);
            }
            set
            {
                SetValue(PatchAvgBytesPerSecProperty, value);
            }
        }
        #endregion Patch AvgBytesPerSec 
        #region Patch BitsPerSample
        public static readonly DependencyProperty PatchBitsPerSampleProperty =
           DependencyProperty.Register("PatchBitsPerSample",
           typeof(int),
           typeof(XA2TabPanelBase),
           new PropertyMetadata(new PropertyChangedCallback(PatchBitsPerSampleChanged)));

        private static void PatchBitsPerSampleChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs args)
        {
            XA2TabPanelBase instance = dependency as XA2TabPanelBase;
            if (instance != null)
            {
                (instance.ResourceRoot.FindName("PART_BitsPerSampleLabel") as Label).Content = instance.PatchBitsPerSample.ToString() + " bits/sample";
            }
        }
        public int PatchBitsPerSample
        {
            get
            {
                return (int)GetValue(PatchBitsPerSampleProperty);
            }
            set
            {
                SetValue(PatchBitsPerSampleProperty, value);
            }
        }
        #endregion Patch BitsPerSample
        #region Patch BlockAlign
        public static readonly DependencyProperty PatchBlockAlignProperty =
            DependencyProperty.Register("PatchBlockAlign",
            typeof(int),
            typeof(XA2TabPanelBase),
            new PropertyMetadata(new PropertyChangedCallback(PatchBlockAlignChanged)));

        private static void PatchBlockAlignChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs args)
        {
            XA2TabPanelBase instance = dependency as XA2TabPanelBase;
            if (instance != null)
            {
                (instance.ResourceRoot.FindName("PART_BlockAlignLabel") as Label).Content = instance.PatchBlockAlign.ToString() + " [blockalign]";
            }
        }
        public int PatchBlockAlign
        {
            get
            {
                return (int)GetValue(PatchBlockAlignProperty);
            }
            set
            {
                SetValue(PatchBlockAlignProperty, value);
            }
        }
        #endregion Patch BlockAlign
        #region Patch WaveFormatEncoding
        public static readonly DependencyProperty PatchWaveFormatEncodingProperty =
            DependencyProperty.Register("PatchWaveFormatEncoding",
            typeof(SharpDX.Multimedia.WaveFormatEncoding),
            typeof(XA2TabPanelBase),
            new PropertyMetadata(new PropertyChangedCallback(PatchWaveFormatEncodingChanged)));

        private static void PatchWaveFormatEncodingChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs args)
        {
            XA2TabPanelBase instance = dependency as XA2TabPanelBase;
            if (instance != null)
            {
                (instance.ResourceRoot.FindName("PART_WaveFormatEncodingLabel") as Label).Content = instance.PatchWaveFormatEncoding.ToString() + " encoding";
            }
        }
        public SharpDX.Multimedia.WaveFormatEncoding PatchWaveFormatEncoding
        {
            get
            {
                return (SharpDX.Multimedia.WaveFormatEncoding)GetValue(PatchWaveFormatEncodingProperty);
            }
            set
            {
                SetValue(PatchWaveFormatEncodingProperty, value);
            }
        }        
        #endregion Patch WaveFormatEncoding
        #region Patch ExtraSize
        public static readonly DependencyProperty PatchExtraSizeProperty =
            DependencyProperty.Register("PatchExtraSize",
            typeof(int),
            typeof(XA2TabPanelBase),
            new PropertyMetadata(new PropertyChangedCallback(PatchExtraSizeChanged)));

        private static void PatchExtraSizeChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs args)
        {
            XA2TabPanelBase instance = dependency as XA2TabPanelBase;
            if (instance != null)
            {
                (instance.ResourceRoot.FindName("PART_ExtraSizeLabel") as Label).Content = instance.PatchExtraSize.ToString() + " extra bytes";
            }
        }
        public int PatchExtraSize
        {
            get
            {
                return (int)GetValue(PatchExtraSizeProperty);
            }
            set
            {
                SetValue(PatchExtraSizeProperty, value);
            }
        }
        #endregion Patch BlockAlign
        #region Patch Size
        public static readonly DependencyProperty PatchSizeProperty =
            DependencyProperty.Register("PatchSize",
            typeof(long),
            typeof(XA2TabPanelBase),
            new PropertyMetadata(new PropertyChangedCallback(PatchSizeChanged)));

        private static void PatchSizeChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs args)
        {
            XA2TabPanelBase instance = dependency as XA2TabPanelBase;
            if (instance != null)
            {
                (instance.ResourceRoot.FindName("PART_SizeLabel") as Label).Content = instance.PatchSize.ToString() + " bytes";
            }
        }
        public long PatchSize
        {
            get
            {
                return (long)GetValue(PatchSizeProperty);
            }
            set
            {
                SetValue(PatchSizeProperty, value);
            }
        }
        #endregion Patch BlockAlign
        #endregion Dependency Properties

        #region Constructors
        protected XA2TabPanelBase()
        {
            if (PatchThread == null)
            {
                PatchThread = Thread.CurrentThread;
            }
            ScheduledXAudio2.Engine.RhythmSettingsChangedNotifier.PropertyChanged += new PropertyChangedEventHandler(RhythmSettingsChangedNotifier_PropertyChanged);
            this.WasSelected += new RoutedEventHandler(PatchTabPanel_WasSelected);
            this.Initialized += XA2TabPanelBase_Initialized;
        }
        
        #endregion Constructors

        #region Methods
        internal void ClearFxChain()
        {
            if (FxChain != null)
            {
                foreach (EffectDescriptor ed in FxChain)
                {
                    if (ed != null)
                        ed.Effect.Dispose();
                }
            }
        }
        public virtual void Dispose() { }       
        /// <summary>
        /// wav names that begin with a number will have a preceding underscore (123DrumSound would be _123DrumSound)
        /// </summary>
        /// <returns></returns>
        public virtual void AddNewRhythmButtonBar() { }
        public static string[] GetIncludedWavs()
        {
            string[] includedWavs = new string[] 
            { 
                "_808Ride",
                "BassDrumRockKick",
                "BigDrumKick",
                "CleanSnareHit",
                "GatedHit",
                "HeavySnareHit",
                "FullOfRobots",
                "CowBell",
                "RockHiHat",
                "_808HighTom2",
                "_909MidTom",
                "_909LowTom",
                "zildjianCymbal",
                "RolandDrumsKick",
                "DiscoHit",
                "DirtyHit",
                "RnB_Stab",
                "BrassHit",
                
            };
            return includedWavs;
        }
        protected static void ChangeIncludedFile(DependencyObject dependency, string newWavSelection)
        {
            XA2TabPanelBase instance = dependency as XA2TabPanelBase;
            if (instance != null)
            { 
            
            }
        }
        protected string GetWavFromResources(string wavfile)
        {
            if (wavfile != null)
            {
                System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom("SynergyLib.dll");
                return String.Format(@"SynergyLib;component/Resources/{0}.wav", wavfile);
            }
            return "wav file not found";
        }
        private void UpdatePatchInfo()
        {
            PatchSampleRate = DrumPatchLoader.LastLoadedPatchInfo.PatchSampleRate;
            PatchAvgBytesPerSec = DrumPatchLoader.LastLoadedPatchInfo.PatchAvgBytesPerSec;
            PatchBitsPerSample = DrumPatchLoader.LastLoadedPatchInfo.PatchBitsPerSample;
            PatchBlockAlign = DrumPatchLoader.LastLoadedPatchInfo.PatchBitsPerSample;
            PatchChannels = DrumPatchLoader.LastLoadedPatchInfo.PatchChannels;
            PatchWaveFormatEncoding = DrumPatchLoader.LastLoadedPatchInfo.PatchWaveFormatEncoding;
            PatchExtraSize = DrumPatchLoader.LastLoadedPatchInfo.PatchExtraBytes;
            PatchSize = DrumPatchLoader.LastLoadedPatchInfo.PatchSize;
        }
        private void GraphCheck()
        {
            if (Grapher == null)
            {
                Grapher = new GraphingEffect();                
            }
            if (GrapherED == null)
            {
                GrapherED = new EffectDescriptor(Grapher);
            }
        }
        protected virtual void ConfigureTabPatch()
        {            
            TabPatch.Tag = DrumPatchControl.CurrentlySelectedTab.Patch;
            Tabs.Add(TabPatch);
            TabPatch.GotFocus += Tab_GotFocus;            
            //Children            
            ComboBoxPatches.SelectionChanged += new SelectionChangedEventHandler(ComboBoxPatches_SelectionChanged);           
            RadioBtnFromFile.Click += AnyRadioBtn_Click;
            RadioBtnSamples.Click += AnyRadioBtn_Click;
            BtnDirectoryBrowse.Click += BtnDirectoryBrowse_Click;
        }        
        protected virtual void ConfigureTabShape()
        {            
            TabShape.Tag = DrumPatchControl.CurrentlySelectedTab.Shape;
            Tabs.Add(TabShape);
            TabShape.GotFocus += Tab_GotFocus;
            //Children
            TabShapePanel.IsVisibleChanged += TabShapePanel_IsVisibleChanged;
        }
        protected virtual void ConfigureTabPattern()
        {
            TabPattern.Tag = DrumPatchControl.CurrentlySelectedTab.Pattern;
            Tabs.Add(TabPattern);
            TabPattern.GotFocus += Tab_GotFocus;
            TabPatternPanel.IsVisibleChanged += TabPatternPanel_IsVisibleChanged;
        }
        protected virtual void ConfigureTabSubmixer()
        {
            TabSubmixer.Tag = DrumPatchControl.CurrentlySelectedTab.Submixer;
            Tabs.Add(TabSubmixer);
            TabSubmixer.GotFocus += Tab_GotFocus;
        }
        protected virtual void ConfigureTabEffects()
        {
            TabEffects.Tag = DrumPatchControl.CurrentlySelectedTab.Effects;
            Tabs.Add(TabEffects);
            TabEffects.GotFocus += Tab_GotFocus;
            //Children
            ButtonAddFx.Click += new RoutedEventHandler(ButtonAddFx_Click);
            ComboBoxSelectFx.ItemsSource = Enum.GetValues(typeof(EffectTypes));
        }
        
      
        public override string ToString()
        {
            return SynergyLib.Friendly.FriendlyFileNameGenerator.GetFriendlyName(FilePath);
        }
        internal override void GetTemplateChildren()
        {           
                if (Bars == null)
                {
                    Bars = new ObservableCollection<RhythmButtonBar>();
                    XA2Sequencer.RegisterBarCollection(this);
                }
                if (Tabs == null)
                {
                    Tabs = new Collection<TabItem>();
                }               
                ConfigureTabPatch();
                ConfigureTabShape();
                ConfigureTabPattern();
                ConfigureTabSubmixer();
                ConfigureTabEffects();

                HasTemplateChildren = true;
        }       
        internal virtual void RefreshTabPatternPanel(bool isVisible)
        {}
        internal virtual void TabPatternPanelRemoveBar() { }
        #endregion Methods

        #region Event Handlers
        protected void PatchTabPanel_WasSelected(object sender, RoutedEventArgs e)
        {
            try
            {
                IsCurrentlySelected = true;
            }
            catch (ArgumentNullException)
            {
                Console.WriteLine("DrumPatchTabPanel_WasSelected threw an ArgumentNullException!");
            }
            catch (NullReferenceException)
            {
                Console.WriteLine("DrumPatchTabPanel_WasSelected threw an NullReferenceException!");
            }
        }
        protected virtual void TabPatternPanel_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (TabPatternPanel != null)
            {
                RefreshTabPatternPanel((bool)e.NewValue);
            }
        }
        void BtnDirectoryBrowse_Click(object sender, RoutedEventArgs e)
        {               
            FileDirectory = SynergyLib.Friendly.FileGetter.ChangeDirectory();
        }
        private void PatchFromStreamComboBoxChanged(ComboBox instance)
        {
            //var item = instance.SelectedItem as System.IO.Stream;
            var item = instance.SelectedItem as string;
            //if (instance.SelectedIndex >= 0)
            if (instance.SelectedItem != null)
            {
                FilePath = instance.SelectedItem.ToString();
                var str = SynergyLib.Bass.ResourceManager.GetStream(instance.SelectedItem.ToString(), null);                
                SoundEngine.Load(str);
                UpdatePatchInfo();
            }
        }
        private void PatchFromFileComboBoxChanged(ComboBox instance)
        {
            try
            {
                if (instance.SelectedItem.ToString().EndsWith(".Wav") || instance.SelectedItem.ToString().EndsWith(".wav"))
                {
                    FilePath = (SynergyLib.Friendly.FileGetter.GetFilesList())[instance.SelectedIndex].FullName;
                    SoundEngine.Load(FilePath);
                    UpdatePatchInfo();
                }
            }
            catch (NullReferenceException)
            {
                System.Windows.MessageBox.Show("PatchFromFileComboBoxChanged() threw a NullReferenceException!");
                return;
            }
        }
        void XA2TabPanelBase_Initialized(object sender, EventArgs e)
        {
            patchsource = PatchSource.FromFilePath;
            GraphCheck();           
        }
        /// <summary>
        /// set the property of selected tag in parent control so that the same tag can be selected when going from one tab panel to another.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void Tab_GotFocus(object sender, RoutedEventArgs e)
        {
            var send = sender as TabItem;
            SelectedTabChanged_OnRaiseEvent((DrumPatchControl.CurrentlySelectedTab)send.Tag, e);
        }
        protected virtual void AnyRadioBtn_Click(object sender, RoutedEventArgs e)
        {
            var radiobtn = sender as RadioButton;            
            if (radiobtn == RadioBtnSamples)
            {
                NewDirectoryTextBox.IsEnabled = false;
                patchsource = PatchSource.FromStream;
            }
            if (radiobtn == RadioBtnFromFile)
            {
                NewDirectoryTextBox.IsEnabled = true;
                patchsource = PatchSource.FromFilePath;
            }
        }
        
        /// <summary>
        /// Removes the static spectrumanalyzer from its parent right quick(if it has one)
        /// before adding it to the newly selected tab.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void TabShapePanel_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (!(bool)e.NewValue && TabShapePanel.Children.Contains(DrumPatchControl.DynamicSpectrumAnalyzer))
            {
                TabShapePanel.Children.Clear();
            }
            if ((bool)e.NewValue)
            {
                GraphCheck();
                if (PrimarySubmixer != null)
                {
                    PrimarySubmixer.SetEffectChain(GrapherED);
                }
                DrumPatchControl.DynamicSpectrumAnalyzer.RegisterSoundPlayer((ISpectrumPlayer)Grapher);
                TabShapePanel.Children.Add(DrumPatchControl.DynamicSpectrumAnalyzer);
            }
        }
        void TabItemParent_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var send = sender as TabItem;
            System.Windows.MessageBox.Show(send.ToString());
        }
        internal void WasSelected_OnRaiseEvent(RoutedEventArgs e)
        {
            if (WasSelected != null)
            {
                WasSelected(this, e);
            }
        }
        /// <summary>
        /// called when a tab is selected in DrumPatchTabPanel to keep the same selected tab when switching tabs
        /// </summary>
        /// <param name="tab"></param>
        /// <param name="e"></param>
        internal void SelectedTabChanged_OnRaiseEvent(DrumPatchControl.CurrentlySelectedTab tab, RoutedEventArgs e)
        {
            if (SelectedTabChanged != null)
            {
                //CurrentTab must be set before raising the event or the tab doesnt get selected because it doesnt have the information it needs
                DrumPatchControl.CurrentTab = tab;
                SelectedTabChanged(this, e);               
            }
        }        
        protected void RhythmSettingsChangedNotifier_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (Bars != null)
            {
                var newsettings = ScheduledXAudio2.Engine.RhythmSettingsChangedNotifier as RhythmSettingsControl;
                var toggler = ScheduledXAudio2.Engine.OnOffNotifier as StartStopControl;

                foreach (RhythmButtonBar b in Bars)
                {
                    if (b.BeatsPerMeasure != newsettings.BeatsPerMeasure)
                    {
                        toggler.OffInvoker.DynamicInvoke(null, null);
                        b.BeatsPerMeasure = newsettings.BeatsPerMeasure;
                    }
                    if (b.EqualsOneBeat != newsettings.EqualsOneBeat)
                    {
                        toggler.OffInvoker.DynamicInvoke(null, null);
                        b.EqualsOneBeat = newsettings.EqualsOneBeat;
                    }
                }
            }
        }
        protected void ComboBoxPatches_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var instance = sender as ComboBox;
            switch (patchsource)
            { 
                case PatchSource.FromStream:
                    PatchFromStreamComboBoxChanged(instance);
                    break;
                case PatchSource.FromFilePath:
                    PatchFromFileComboBoxChanged(instance);
                    break;
            }           
        }
        protected void ButtonAddFx_Click(object sender, RoutedEventArgs e)
        {
            if (ComboBoxSelectFx != null && ComboBoxSelectFx.SelectedValue != null)
            {
                var val = ComboBoxSelectFx.SelectedValue;
                Type t = val.GetType();

                if (FxChain != null)
                {
                    EffectsPanel newEffect;

                    switch (val.ToString())
                    {
                        case "Chorus":
                            newEffect = new ChorusPanel(PrimarySubmixer, FxChain);
                            break;
                        case "Flanger":
                            newEffect = new FlangerPanel(PrimarySubmixer, FxChain);
                            break;
                        case "Tremolo":
                            newEffect = new TremoloPanel(PrimarySubmixer, FxChain);
                            break;
                        case "DelayVibrato":
                            newEffect = new DelayVibratoPanel(PrimarySubmixer, FxChain);
                            break;
                        case "Limiter":
                            newEffect = new LimiterPanel(PrimarySubmixer, FxChain);
                            break;
                        case "RingModulation":
                            newEffect = new RingModulationPanel(PrimarySubmixer, FxChain);
                            break;
                        case "Schroeder":
                            newEffect = new SchroederPanel(PrimarySubmixer, FxChain);
                            break;
                        case "ShelvingPeakFilter":
                            newEffect = new ShelvingPeakFilterPanel(PrimarySubmixer, FxChain);
                            break;
                        default:
                            return;
                    }
                    if (newEffect != null)
                        TabEffectsPanel.Children.Add(newEffect);
                }
            }

        }
        /// <summary>
        /// DrumPatchTabPanels are on the same thread as DrumPatchControls now so the AddNewRhythmButtonBar() 
        /// method no longer needs to be called through a delegate.  
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void ParentRef_PropertyChanged(object sender, PropertyChangedEventArgs e) { }
       
        #endregion Event Handlers

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        #endregion
    }
}
